//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<object_factory.h>
///	@path	~/src/object/
///	@date	2007/06/27
///	@desc	Object factory, manages all instance of IObject's creation & destruction.

#pragma once

#include "xeres.h"

#include "lib/utilities/string.h"

#include "object/class_id.h"
#include "object/IObject.h"

namespace xeres {

	/*!
		\ingroup iobject_module

		\class	ObjectFactory
		\brief	Produce IObject instances & manage memory allocation.
		\details
			All IObject classes should produce objects from this class.
			Object factory maintains a map of registered interfaces and classes,
			manages inheritance relationship and RTTI, instancing objects from class creator.<BR>
			<BR>
			In most cases, user should use new operator to create instance:
			\code
				Ref<IVar> var = new CVar;
			\endcode
			Or in some cases, we need to create instance dynamically by calling CreateObject:<BR>
			\code
				Ref<IVar> var = ObjectFactory::CreateObject( "CVar" );
			\endcode
			<BR>

		\par About class registration:
			Class registration is done by IObject, user should not implement any registration detail.
			To manual register a class, use \ref IOBJECT_REGISTER_CLASS.

		\remarks
			<b>Never</b> try to delete any instance of IObject!<BR>
			To Release an instance, just call IObject::ReleaseRef and it will be deleted while no reference.

		\sa		IObject
	*/
	class ObjectFactory
	{
	public:

		/// \name Interface & Class Registration
		//@{

		/*!
			\brief		Object construction protocol.
			\details	A function protocol used in object construction.
						Usually this pointer points to a function generated by
						/ref IMPL_IOBJECT_CLASS_DYNAMIC.
		*/
		typedef IObject * (*ConstructObjectFn)( void * );

		/*!
			\brief		Register class and create inheritance table.
			\details	Register a class(can be instanced) in object factory.
						<I>This function is called by internal object registration mechanism,
						user should not use this function to register classes.</I>
			\return		Destination class ID.
			\param[in]	name			Class name.
			\param[in]	ancient			Ancient class ID.
			\param[in]	constructor		Construction function.
			\param[in]	size			Instance size in byte.
		*/
		static ClassID RegisterClass( const WString& name , const ClassID ancient ,
			ConstructObjectFn constructor , size_t size );

		/*!
			\brief		Register interface and create inheritance table.
			\details	Register an interface(cannot be instanced) in object factory.
						<I>This function is called by internal object registration mechanism,
						user should not use this function to register classes.</I>
			\remarks	Register interface is used to build inheritance hierarchy.
						Any interface is not actually used or instanced.
			\return		Destination interface ID.
			\param[in]	name		Interface name.
			\param[in]	ancient		Ancient interface ID.
		*/
		static ClassID RegisterInterface( const WString& name , const ClassID ancient );

		//@}

		/// \name Object Instancing
		//@{

		/*!
			\brief		Create object instance from a given string.
			\details	Create object by a given class name. The factory will select proper registered
						class from class table and allocate proper space for it, run specific construction
						function.<BR>
						This function only works on dynamic classes, which defined by
						/ref IMPL_IOBJECT_CLASS_DYNAMIC. Static classes cannot be instanced by this function.
			\return		New object instance.
			\param[in]	name	Class name.
		*/
		static IObject * CreateObject( const WString& name );

		/*!
			\brief		Create object instance from a given ID.
			\details	Create object by a given class ID. The factory will select proper registered
						class from class table and allocate proper space for it, run specific construction
						function.<BR>
						This function only works on dynamic classes, which defined by
						/ref IMPL_IOBJECT_CLASS_DYNAMIC. Static classes cannot be instanced by this function.
			\return		New object instance.
			\param[in]	id		Class id.
		*/
		static IObject * CreateObject( const ClassID id );

		//@}

		/// \name RIIT Function
		//@{

		/*!
			\brief		Determine if 2 class is compatible.
			\details	The core of RTTI is determine if 2 types are compatible at runtime.<BR>
						In xeres, classes are registered & organized by a inheritance map.
						IObject interfaces & classes recognizes their ancient(super) classes.
						So by finding entry in inheritance map can determine if a class inherits from another.<BR>
						This function simpily finds if 'child' has an entry of 'ancient' in its inheritnace map,
						to determine if a an ancient object can be cast to a child object or not.
						\eg			Demonstrates how RTTI works.
						\code
							// We have an IVar object passed in,
							// and we want to know if it actually is an CVar.
							Ref<IVar> var;
							if( ObjectFactory::IsCompatible( var->GetClassID() , CVar::StaticClassID() ) )
							{
								Ref<CVar> cvar( var );
							}
						\endcode
						In fact, the way used in the example is not recommended.
						Use IObject::IsA will be more efficient.
						\code
							// Doing the same thing as above.
							if( var->IsA<CVar>() )
							{
								Ref<CVar> cvar( var );
							}
						\endcode
						<b>Notice that Ref implements type cast check inside constructor.</b>
			\param[in]	child		Child class id.
			\param[in]	ancient		Ancient class id.

			\sa			Ref, IObject::IsA
		*/
		static bool IsCompatible( ClassID child , ClassID ancient );

		//@}

	private:

		friend class IObject;
		friend class IBuffer;

		/// \name Object Instancing
		//@{

		/*!
			\brief		Allocate new space for object
			\details
			\return		New space address for object.
			\param[in]	size	Space size.
			\param[in]	id		Class id.
		*/
		static void * AllocateObject( size_t size , const ClassID id );

		/*!
			\brief		Deallocate object instance space.
			\details
			\param[in,out]	ptr		Object address.
			\param[in]		id		Class id.
		*/
		static void DeallocateObject( void * ptr , const ClassID id );

		/*!
			\brief		Allocate new space for buffer. Only IBuffer call it.
			\details	Special allocation function for IBuffer.
			\return		New space address for buffer.
			\param[in]	size	Space size.

			\sa			IBuffer
		*/
		static void * AllocateBuffer( size_t size );

		/*!
			\brief		Deallocate buffer space.
			\details	Special deallocation function for IBuffer.
			\param[in,out]		ptr		Buffer address.
			\param[in]			size	Buffer size.

			\sa			IBuffer
		*/
		static void DeallocateBuffer( void * ptr , size_t size );
		//@}

		/// \name Interface & Class Registration
		//@{

		/*!
			\brief		Register IBuffer class.
			\details	Special function for IBuffer registration.
			\sa			IBuffer
			\param[in]	name		Class name, should be "IBuffer".
			\param[in]	ancient		Ancient class name, should be "IObject".
		*/
		static ClassID RegisterIBuffer(
			const WString& name /* should be 'IBuffer' */ ,
			const ClassID ancient /* should be IObject */ );

		/*!
			\brief		Register basic type. Only for IObject first register use.
			\details
			\param[in]	name	Basic type name.
			\param[in]	size	Type size.
			\param[in]	id		Type id.
		*/
		static void RegisterType( const WString& name , size_t size , const ClassID id );

		//@}

		/// \name Constructor & Destructor
		//@{

		/// @ctor_disabled
		ObjectFactory( void );

		//@}
	};

} // namespace xeres
